package hikari.objects3d;

import com.gooddies.wiring.Wiring;
import hikari.gui.panels.bullet.BulletPhysicsPanel;
import hikari.hcomponents.HComponent;
import hikari.hcomponents.physics.PhysicsData;
import hikari.managers.Manager3D;
import hikari.managers.undo.Undo;
import hikari.persistence.file.FileSection;
import hikari.persistence.file.PersistenceSection;
import hikari.template.Template;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.swig.jirr.IAnimatedMeshSceneNode;
import org.swig.jirr.IMesh;
import org.swig.jirr.IMeshSceneNode;
import org.swig.jirr.ISceneNode;
import org.swig.jirr.ITriangleSelector;
import org.swig.jirr.aabbox3df;
import org.swig.jirr.vector3df;

public abstract class Basic3dObject {

    private String objectName;
    private ISceneNode node;
    private static Map<String, Integer> nameCount = new HashMap<>();
    private ArrayList<HComponent> components = new ArrayList<>();
    private Template template;
    private boolean freezed = false;
    private boolean visible = true;
    private ITriangleSelector selector;

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    public Basic3dObject(String objectName) {
        this(objectName, false);
    }

    public boolean isFreezed() {
        return freezed;
    }

    public void setFreezed(boolean freezed) {
        this.freezed = freezed;
    }

    public Template getTemplate() {
        return template;
    }

    public void setTemplate(Template template) {
        this.template = template;
    }

    public List<HComponent> getEditPanels() {
        List<HComponent> newArrayList = new ArrayList<HComponent>();
        for (HComponent comp : components) {
            if (comp instanceof PhysicsData) {
                newArrayList.add(Wiring.getComponent(BulletPhysicsPanel.class).loadFromModel(this, (PhysicsData) comp));
            } else {
                newArrayList.add(comp);
            }
        }
        return newArrayList;
    }

    public void addHComponent(HComponent component) {
        if (component == null) {
            throw new RuntimeException("Cannot add null component");
        }
        components.add(component);
    }

    public void removeHComponent(HComponent component) {
        if (component == null) {
            throw new RuntimeException("Cannot remove null component");
        }
        components.remove(component);
    }

    public Basic3dObject setMeshSceneNode(ISceneNode node) {
        this.node = node;
        return this;
    }

    public aabbox3df getBoundingBox() {
        return getMeshSceneNode().getBoundingBoxConst();
    }

    public ISceneNode getMeshSceneNode() {
        return node;
    }

    public Basic3dObject(String objectName, boolean generateIndex) {
        String name;
        if (generateIndex) {
            name = getNewIndex(objectName);
        } else {
            name = objectName;
        }
        this.objectName = name;
    }

    private String getNewIndex(String name) {
        Integer integer = nameCount.get(name);
        if (integer == null || integer == 0) {
            integer = 0;
        }
        integer = integer + 1;
        nameCount.put(name, integer);
        return name + integer;
    }

    public vector3df getPosition() {
        return node.getPosition();
    }

    public Basic3dObject setPosition(vector3df position) {
        node.setPosition(position);
        return this;
    }

    public vector3df getPositionWithUndo() {
        return getPosition();
    }

    public Basic3dObject setPositionWithUndo(vector3df position) {
        Wiring.getComponent(Undo.class).createPojoUndo(this);
        return setPosition(new vector3df(position.getX(), position.getY(), position.getZ()));
    }

    public Basic3dObject setRotationWithUndo(vector3df rotation) {
        Wiring.getComponent(Undo.class).createPojoUndo(this);
        return setRotation(rotation);
    }

    public vector3df getRotationWithUndo() {
        return getRotation();
    }

    public Basic3dObject setScalingWithUndo(vector3df scale) {
        Wiring.getComponent(Undo.class).createPojoUndo(this);
        return setScaling(scale);
    }

    public vector3df getScalingWithUndo() {
        return getScaling();
    }

    public vector3df getRotation() {
        return node.getRotation();
    }

    public Basic3dObject setRotation(vector3df rotation) {
        System.out.println("rotation " + rotation.toString());
        node.setRotation(rotation);
        return this;
    }

    public vector3df getScaling() {
        return node.getScale();
    }

    public Basic3dObject setScaling(vector3df scaling) {
        node.setScale(scaling);
        return this;
    }

    public String getObjectName() {
        return objectName;
    }

    public Basic3dObject setObjectName(String objectName) {
        this.objectName = objectName;
        return this;
    }

    @Override
    public String toString() {
        return objectName;
    }

    public abstract String objectType();

    public final void write(FileSection writer, int parentId, int currentId) {
        try {
            PersistenceSection section = writer.createNewSection("3dObject");
            section.writeString("ObjT", objectType());
            if (parentId != -1) {
                section.writeInt("parent", parentId);
            }
            section.writeInt("id", currentId);
            writeData(section);
            section.close();
        } catch (IOException ex) {
            Logger.getLogger(Basic3dObject.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    protected void writeVector(vector3df vector, PersistenceSection writer) throws IOException {
        writer.writeFloat("x", vector.getX());
        writer.writeFloat("y", vector.getY());
        writer.writeFloat("z", vector.getZ());
    }

    public void writeData(FileSection section) throws IOException {
        PersistenceSection transformSection = section.createNewSection("tfm");
        transformSection.writeString("name", objectName);

        PersistenceSection positionSection = transformSection.createNewSection("pos");
        writeVector(node.getPosition(), positionSection);
        positionSection.close();
        PersistenceSection rotationSection = transformSection.createNewSection("rot");
        writeVector(node.getRotation(), rotationSection);
        rotationSection.close();
        PersistenceSection scaleSection = transformSection.createNewSection("scl");
        writeVector(node.getScale(), scaleSection);
        scaleSection.close();
        transformSection.close();
        boolean isObjectUpdateable = false;
        for (HComponent component : components) {
            component.writeData(section);
            if (isObjectUpdateable == false) {
                if (component.isObjectUpdateable()) {
                    isObjectUpdateable = true;
                }
            }
        }

        section.writeBoolean("updtbl", isObjectUpdateable);
        section.writeBoolean("freez", isFreezed());
    }

    public boolean onRemove() {
        return true;
    }

    public void freeze(boolean freeze) {

        if (freeze) {
            if (isFreezed()) {
                return;
            }
            IMesh mesh = null;
            if (node instanceof IMeshSceneNode) {
                mesh = ((IMeshSceneNode) node).getMesh();
            } else if (node instanceof IAnimatedMeshSceneNode) {
                mesh = ((IAnimatedMeshSceneNode) node).getMesh();
            }
            selector = node.getTriangleSelector();
            node.setTriangleSelector(null);
            if (mesh != null) {
                Wiring.getComponent(Manager3D.class).getSceneManager().getMeshManipulator().setVertexColorAlpha(mesh, 50);
            }
        } else {
            if (!isFreezed()) {
                return;
            }
            IMesh mesh = null;
            if (node instanceof IMeshSceneNode) {
                mesh = ((IMeshSceneNode) node).getMesh();
            } else if (node instanceof IAnimatedMeshSceneNode) {
                mesh = ((IAnimatedMeshSceneNode) node).getMesh();
            }
            node.setTriangleSelector(selector);
            if (mesh != null) {
                Wiring.getComponent(Manager3D.class).getSceneManager().getMeshManipulator().setVertexColorAlpha(mesh, 255);
            }
        }
        setFreezed(freeze);
    }
}
